<!DOCTYPE html>
<html>
  <head>
    <title>
      ScriptProcessorNode on OfflineAudioContext
    </title>
    <script src="../../resources/testharness.js"></script>
    <script src="../../resources/testharnessreport.js"></script>
    <script src="../resources/audit-util.js"></script>
    <script src="../resources/audit.js"></script>
  </head>
  <body>
    <script id="layout-test-code">
      let audit = Audit.createTaskRunner();


      // Fill the output of script processor with a constant value.
      audit.define('simple-output', (task, should) => {
        let sampleRate = 44100;
        let scriptBufferSize = 256;
        let renderLength = 1;
        let PI = Math.fround(Math.PI);

        let context =
            new OfflineAudioContext(1, renderLength * sampleRate, sampleRate);

        let scriptNode = context.createScriptProcessor(scriptBufferSize, 1, 1);
        scriptNode.onaudioprocess = function(event) {
          let outputChannel = event.outputBuffer.getChannelData(0);
          outputChannel.fill(PI);
        };
        scriptNode.connect(context.destination);

        context.startRendering().then(function(buffer) {
          let channel = buffer.getChannelData(0);
          let initialDelay = channel.subarray(0, 2 * scriptBufferSize);
          let actualContent = channel.subarray(2 * scriptBufferSize);

          // There is the initial delay (2 x buffer size) which is silent.
          should(initialDelay, 'The initial delay contains zeros.')
              .beConstantValueOf(0);

          // After the initial delay, we must get |PI|.
          should(actualContent, 'The actual content contains ' + PI)
              .beConstantValueOf(PI);

          task.done();
        });
      });


      // Pass through an oscillator via a script processor. Sum with the
      // phase-inverted oscillator with the delayed start time. Verify the
      // rendered buffer is completely silent.
      audit.define('oscillator-output', (task, should) => {
        let sampleRate = 44100;
        let scriptBufferSize = 256;
        let renderLength = 1;

        let context =
            new OfflineAudioContext(1, renderLength * sampleRate, sampleRate);

        let osc1 = context.createOscillator();
        let osc2 = context.createOscillator();
        let inverter = context.createGain();
        let scriptNode = context.createScriptProcessor(scriptBufferSize, 1, 1);
        scriptNode.onaudioprocess = function(event) {
          let inputChannel = event.inputBuffer.getChannelData(0);
          let outputChannel = event.outputBuffer.getChannelData(0);
          outputChannel.set(inputChannel);
        };

        inverter.gain.value = -1;

        osc1.connect(inverter).connect(context.destination);
        osc2.connect(scriptNode).connect(context.destination);

        // The delayed start for |osc1|.
        osc1.start((2 * scriptBufferSize) / sampleRate);
        osc2.start();

        context.startRendering().then(function(buffer) {
          let channel = buffer.getChannelData(0);

          // The rendered buffer must be silent.
          should(channel, 'The rendered buffer').beConstantValueOf(0);

          task.done();
        });
      });

      audit.run();
    </script>
  </body>
</html>
